#include "include/kconst.h"
#include "include/type.h"
#include "include/console.h"
#include "include/tty.h"
#include "include/klib.h"
#include "include/global.h"
extern TTY tty_table[NR_CONSOLES];
extern CONSOLE console_table[NR_CONSOLES];
extern u32 nr_current_console;


#define CRTC_ADDR_REG 0x3D4
#define CRTC_DATA_REG 0x3D5
#define START_ADDR_H  0xC
#define START_ADDR_L  0xD
#define CURSOR_H      0xE
#define CURSOR_L      0xF

void set_cursor(u32 pos)
{
    disable_int();
    out_byte(CRTC_ADDR_REG, CURSOR_H);
    out_byte(CRTC_DATA_REG, (pos >> 8) & 0xFF);
    out_byte(CRTC_ADDR_REG, CURSOR_L);
    out_byte(CRTC_DATA_REG, (pos) & 0xFF);
    enable_int();
}

void flush(CONSOLE *p_con)
{
    set_cursor(p_con->cursor);
    set_video_start_addr(p_con->current_start_addr);
}

void out_char(CONSOLE *p_con, char ch)
{
    u8 *p_vmem = (u8*) (V_MEM_BASE + (p_con->cursor << 1));

    switch (ch)
    {
    case '\n':
        p_con->cursor = (p_con->original_addr + 80 *
            ((p_con->cursor - p_con->original_addr)/ 80 + 1));
        p_vmem = (u8*) (V_MEM_BASE + (p_con->cursor << 1));
        *p_vmem++ = ' ';
        *p_vmem++ = 0x000F;
        break;
    case '\b':
        *(p_vmem-2) = ' ';
        *(p_vmem-1) = 0x000F;
        p_con->cursor--;
        break;
    default:
        *p_vmem++ = ch;
        *p_vmem++ = 0x000F;
        *p_vmem++ = ' ';
        *p_vmem++ = 0x000F;
        p_con->cursor++;
        break;
    }

    //屏幕滚动代码
    //TODO
    if (p_con == &console_table[nr_current_console])
        flush(p_con);
}

int is_current_console(CONSOLE *p_con)
{
    return (p_con == &console_table[nr_current_console]);
}

void init_screen(TTY *p_tty)
{
    int nr_tty = p_tty - tty_table;
    p_tty->p_console = console_table + nr_tty;
    int v_mem_size = V_MEM_SIZE >> 1;
    int con_v_mem_size = v_mem_size / NR_CONSOLES;
    p_tty->p_console->original_addr = nr_tty * con_v_mem_size;
    p_tty->p_console->v_mem_limit = con_v_mem_size;
    p_tty->p_console->current_start_addr = p_tty->p_console->original_addr;

    p_tty->p_console->cursor = p_tty->p_console->original_addr;
    if (nr_tty == 0)
    {
        p_tty->p_console->cursor = 400;
    } else 
    {
        out_char(p_tty->p_console, nr_tty + '0');
        out_char(p_tty->p_console, '#');
    }
}

void set_video_start_addr(u32 addr)
{
    disable_int();
    out_byte(CRTC_ADDR_REG, START_ADDR_H);
    out_byte(CRTC_DATA_REG, (addr>>8) & 0xFF);
    out_byte(CRTC_ADDR_REG, START_ADDR_L);
    out_byte(CRTC_DATA_REG, (addr & 0xFF));
    enable_int();
}

void scroll_screen(CONSOLE *p_con, int dir)
{
    if (dir == 0x1)
    {
        if (p_con->current_start_addr > p_con->original_addr) 
        {
            p_con->current_start_addr -= 80;
        }
    } else if (dir == 0x2)
    {
        p_con->current_start_addr += 80;
    }
    flush(p_con);
}

void select_console(u32 nr_console)
{
    if (nr_console >= NR_CONSOLES)
        return;
    nr_current_console = nr_console;
    set_cursor(console_table[nr_current_console].cursor);
    set_video_start_addr(console_table[nr_current_console].current_start_addr);
}